package com.soyotec.algorithm.algorithm;

import com.soyotec.algorithm.context.OptAlgorithmContext;
import com.soyotec.algorithm.enums.ExecutionStatusEnum;
import com.soyotec.algorithm.problem.Problem;
import com.soyotec.algorithm.solution.ValueWrapSolution;
import com.soyotec.algorithm.solution.value.SolutionValue;
import com.soyotec.algorithm.status.ExecutionStatus;
import com.soyotec.algorithm.status.StatusGetter;
import com.soyotec.algorithm.util.file.FileEditor;
import com.soyotec.algorithm.util.file.FileResolver;
import com.soyotec.algorithm.value.DoubleValue;
import com.soyotec.algorithm.value.IntegerValue;
import com.soyotec.algorithm.value.Value;
import weka.core.Instance;
import weka.core.Instances;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public abstract class AbstractOPTFileExchangeAlgorithmPlugin implements OPTFileExchangeAlgorithmPlugin {
    private String[] commandLines;

    private long intervalTime = 200;  //默认间隔时间是200ms

    private Problem<ValueWrapSolution> problem;
    private FileResolver fileResolver = new FileResolver();
    private FileEditor fileEditor = new FileEditor(fileResolver);
    private OptAlgorithmContext optAlgorithmContext;
    private Map<String, Object> algorithmParameter;
    private ExecutorService executorService = Executors.newCachedThreadPool();
    private Map<Integer, ValueWrapSolution> solutionMap;

    private List<Double> resultVariables;



    @Override
    public void run(){
        try {
            // 先创建文件
            System.out.println("开始创建文件");
            init();
            System.out.println("文件创建完成");
            // 2 执行命令
            StatusGetter statusGetter = new StatusGetter();
            if (commandLines != null && commandLines.length > 0) {
                executorService.execute(() -> {
                    try {
                        System.out.println("另一个线程里命令行开始执行");
                        int code = optAlgorithmContext.runSystemCommand(commandLines);
                        if(code == 0){
                            statusGetter.setStatus(true);
                        } else {
                            statusGetter.setStatus(false);
                        }
//                if(code != 0){
//                    throw new Exception(ErrorCode.getTitle(code));
//                }
                        System.out.println("另一个线程里命令执行完了,code" + code);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                });
                //3 解析execution_status.txt
                Boolean execStatus = statusGetter.getStatus();
                int numInstances = 0;
                int numAttribute = 0;
                //退出死循环的条件就是：命令执行完了
                while (execStatus == null) {
                    try {
                        Thread.currentThread().sleep(intervalTime);
                        ExecutionStatus executionStatus = fileResolver.executionStatusFileResolver(optAlgorithmContext.getWorkDir().getAbsolutePath());
                        if(executionStatus != null){
                            Integer code = executionStatus.getCode();
                            if (code != null) {
                                switch (code) {
                                    case 1:
                                        //1 读取runtime_variable.arff
                                        List<ValueWrapSolution> doubleSolutionList = new ArrayList<>();
                                        Instances varInstances = fileResolver.runtimeVariableFileResolver(optAlgorithmContext.getWorkDir().getAbsolutePath());
                                        numInstances = varInstances.numInstances();
                                        numAttribute = varInstances.numAttributes();
                                        for (int i = 0; i < numInstances; i++) {
                                            ValueWrapSolution doubleSolution = problem.createSolution();
                                            for (int j = 1; j < numAttribute; j++) {
                                                Instance instance = varInstances.get(i);
                                                Value value = doubleSolution.getVariableValue(j-1).getValue();
                                                if(value instanceof IntegerValue){
                                                    IntegerValue integerValue = (IntegerValue) value;
                                                    integerValue.setDoubleValue(Double.valueOf(instance.toString(j, 20)));
                                                } else if(value instanceof DoubleValue){
                                                    DoubleValue doubleValue = (DoubleValue) value;
                                                    doubleValue.setDoubleValue(Double.valueOf(instance.toString(j, 20)));
                                                }

//                                                doubleSolution.getVariableValue(j-1).getValue().setValue(Double.valueOf(instance.toString(j, 20)));

                                                System.out.println("===========设计变量取值："+ Double.valueOf(instance.toString(j, 20)));
                                            }
                                            doubleSolutionList.add(doubleSolution);
                                        }
                                        //2 调用子流程
                                        problem.evaluate(doubleSolutionList);
                                        //3 存map
                                        for (ValueWrapSolution doubleSolution : doubleSolutionList) {
                                            List<SolutionValue> variables = doubleSolution.getVariables();
                                            List<Double> value = new ArrayList<>();
                                            for(SolutionValue solutionValue : variables){
                                                value.add(solutionValue.getValue().getDoubleValue());
                                            }
                                            solutionMap.put(arrayHashCode(value), doubleSolution);
                                        }
                                        //4 回写约束和目标
                                        fileEditor.updateRuntimeConstraintFile(optAlgorithmContext.getWorkDir().getAbsolutePath(), doubleSolutionList);
                                        fileEditor.updateRuntimeObjectiveFile(optAlgorithmContext.getWorkDir().getAbsolutePath(), doubleSolutionList);
                                        //5 更新execution_status.txt
                                        fileEditor.updateExecutionStatus(optAlgorithmContext.getWorkDir().getAbsolutePath(),
                                                new ExecutionStatus(ExecutionStatusEnum.SUB_PROCESS_COMPUTED.getCode(), ExecutionStatusEnum.SUB_PROCESS_COMPUTED.getTitle()));
                                        break;
                                    case 2:
                                        break;
                                    case 3:
                                        break;
                                }
                            }
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    execStatus = statusGetter.getStatus();
                }
                if(execStatus){
                    //读取result.arff
                    Instances resultInstances = fileResolver.resultFileResolver(optAlgorithmContext.getWorkDir().getAbsolutePath());
                    numInstances = resultInstances.numInstances();
                    resultVariables = new ArrayList<>();
                    for (int i = 0; i < numInstances; i++) {
                        ValueWrapSolution doubleSolution = problem.createSolution();
                        int variables = doubleSolution.getNumberOfVariables();
                        Instance instance = resultInstances.get(i);
                        for (int j = 0; j < variables; j++) {
                            resultVariables.add(Double.valueOf(instance.toString(j + 1, 20)));
                        }
                    }
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        //把现在SQPDFO run()方法里除了生成命令行之外的代码贴过来
    }

    public void init() {
        //创建各种文件
        if (problem != null) {
            ValueWrapSolution solution = problem.createInitSolution();
            fileEditor.createVariableFile(optAlgorithmContext.getWorkDir().getAbsolutePath(), solution);
            fileEditor.createConstraintFile(optAlgorithmContext.getWorkDir().getAbsolutePath(), solution);
            fileEditor.createObjectiveFile(optAlgorithmContext.getWorkDir().getAbsolutePath(), solution);
            fileEditor.createAlgorithmParameterFile(optAlgorithmContext.getWorkDir().getAbsolutePath(), algorithmParameter);
            fileEditor.createRuntimeVariableFile(optAlgorithmContext.getWorkDir().getAbsolutePath(), solution);
            fileEditor.createRuntimeConstraintFile(optAlgorithmContext.getWorkDir().getAbsolutePath(), solution);
            fileEditor.createRuntimeObjectiveFile(optAlgorithmContext.getWorkDir().getAbsolutePath(), solution);
            fileEditor.createResultFile(optAlgorithmContext.getWorkDir().getAbsolutePath(), solution);
            fileEditor.createExecutionStatusFile(optAlgorithmContext.getWorkDir().getAbsolutePath());
        }
    }

    public int arrayHashCode(double[] array) {
        if (array == null) {
            return 0;
        }
        StringBuffer codeBuffer = new StringBuffer();
        for (double v : array) {
            codeBuffer.append(v);
        }
        return codeBuffer.toString().hashCode();
    }

    public int arrayHashCode(List<Double> array) {
        if (array == null) {
            return 0;
        }
        StringBuffer codeBuffer = new StringBuffer();
        for (double v : array) {
            codeBuffer.append(v);
        }
        return codeBuffer.toString().hashCode();
    }

    public ValueWrapSolution getResult() {
        if (resultVariables != null) {
            return solutionMap.get(arrayHashCode(resultVariables));
        }
        return null;
    }

    @Override
    public void initCommandLines(String[] commandLines){
        this.commandLines = commandLines;
    }

    @Override
    public void initIntervalTime(long intervalTime) {
        this.intervalTime = intervalTime;
    }

    public OptAlgorithmContext getOptAlgorithmContext() {
        return optAlgorithmContext;
    }

    public void setOptAlgorithmContext(OptAlgorithmContext optAlgorithmContext) {
        this.optAlgorithmContext = optAlgorithmContext;
    }

    public Problem<ValueWrapSolution> getProblem() {
        return problem;
    }

    public void setProblem(Problem<ValueWrapSolution> problem) {
        this.problem = problem;
    }

    public Map<String, Object> getAlgorithmParameter() {
        return algorithmParameter;
    }

    public void setAlgorithmParameter(Map<String, Object> algorithmParameter) {
        this.algorithmParameter = algorithmParameter;
    }

    public Map<Integer, ValueWrapSolution> getSolutionMap() {
        return solutionMap;
    }

    public void setSolutionMap(Map<Integer, ValueWrapSolution> solutionMap) {
        this.solutionMap = solutionMap;
    }
}
